package com.letao.server.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.letao.server.dto.BatchSeckillInfoDTO;
import com.letao.server.dto.PageDTO;
import com.letao.server.dto.Result;
import com.letao.server.entity.OrderDetailSeckill;
import com.letao.server.entity.OrderInfo;
import com.letao.server.entity.SeckillInfo;
import com.letao.server.mapper.SeckillInfoMapper;
import com.letao.server.service.IOrderDetailSeckillService;
import com.letao.server.service.IOrderService;
import com.letao.server.service.IOrderStatusLogService;
import com.letao.server.service.ISeckillService;
import com.letao.server.utils.RedisIdWorker;
import com.letao.server.utils.UserHolderUtils;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.aop.framework.AopContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Service
@Slf4j
public class SeckillServiceImpl extends ServiceImpl<SeckillInfoMapper, SeckillInfo> implements ISeckillService {

    @Resource
    SeckillInfoMapper seckillInfoMapper;

    @Resource
    RedisIdWorker redisIdWorker;

    @Resource
    IOrderDetailSeckillService orderDetailSeckillService;

    @Resource
    IOrderService orderService;

    @Resource
    private IOrderStatusLogService orderStatusLogService;

    @Resource
    private RabbitTemplate rabbitTemplate;

    @Override
    public Result getPage(Long page, Long pageSize) {
        IPage<SeckillInfo> iPage = new Page<>(page, pageSize);
        QueryWrapper<SeckillInfo> wrapper = new QueryWrapper<>();
        wrapper.ge("end_time", LocalDateTime.now());
        wrapper.gt("stock", 0);
        wrapper.orderByAsc("begin_time");
        wrapper.eq("bit", 1);
        IPage<SeckillInfo> seckillPage = seckillInfoMapper.selectPage(iPage, wrapper);
        PageDTO<BatchSeckillInfoDTO> pageDTO = new PageDTO<>();

        List<SeckillInfo> records = seckillPage.getRecords();
        for (SeckillInfo record : records) {
            record.setBit(null);
            record.setCreateTime(null);
            record.setModifiedTime(null);
        }
        List<BatchSeckillInfoDTO> batchSeckillInfoDTOList = new ArrayList<>();
        for (SeckillInfo info : records) {
            BatchSeckillInfoDTO batchSeckillInfoDTO = BeanUtil.copyProperties(info, BatchSeckillInfoDTO.class);
            batchSeckillInfoDTO.setSales(info.getNum() - info.getStock());

            if (batchSeckillInfoDTO.getBeginTime().isAfter(LocalDateTime.now()))
                batchSeckillInfoDTO.setSeckillState(0);
            else if (batchSeckillInfoDTO.getEndTime().isBefore(LocalDateTime.now())) {
                batchSeckillInfoDTO.setSeckillState(2);
            } else
                batchSeckillInfoDTO.setSeckillState(1);

            batchSeckillInfoDTOList.add(batchSeckillInfoDTO);
        }


        pageDTO.setRows(batchSeckillInfoDTOList);
        pageDTO.setTotalSize(seckillPage.getTotal());
        pageDTO.setPageSize(seckillPage.getSize());
        pageDTO.setCurrentPage(seckillPage.getCurrent());
        pageDTO.setPages(seckillPage.getPages());
        return Result.success(pageDTO);
    }

    @Override
    public Result seckillOrder(Long id, OrderInfo orderInfo) {
        SeckillInfo info = getById(id);
        if (info == null) {
            return Result.fail("依赖不存在");
        }
        if (info.getBit() == 0) {
            return Result.fail("商品已删除");
        }
        LocalDateTime beginTime = info.getBeginTime();
        LocalDateTime endTime = info.getEndTime();
        if (beginTime.isAfter(LocalDateTime.now()) || endTime.isBefore(LocalDateTime.now())) {
            return Result.fail("不在活动时间内");
        }


        if (info.getStock() < 1) {
            return Result.fail("库存不足");
        }
        Long userId = UserHolderUtils.getUser().getId();
        synchronized (userId.toString().intern()) {
            ISeckillService proxy = (ISeckillService) AopContext.currentProxy();
            return proxy.createOrder(id, orderInfo, info);
        }

    }

    @Transactional
    public Result createOrder(Long id, OrderInfo orderInfo, SeckillInfo info) {
        Long userId = UserHolderUtils.getUser().getId();

        Long count = orderDetailSeckillService.query()
                .eq("user_id", userId)
                .eq("seckill_id", id)
                .eq("bit", 1).count();
        if (count > 0) {
            return Result.fail("秒杀商品不允许一人多单");
        }
        boolean success = update()
                .setSql("stock = stock - 1")
                .eq("id", id)
                .gt("stock", 0)
                .update();
        if (!success) {
            return Result.fail("库存不足");
        }
//        return Result.success();
        Long seckillNumber = redisIdWorker.nextId(info.getName());
        orderInfo.setIsSeckill(1);
        orderInfo.setOrderMoney(info.getConstPrice());

        orderInfo.setUserId(userId);
        orderInfo.setPaymentMethod(0);
        orderInfo.setOrderNumber(info.getName());
        orderService.save(orderInfo);
        OrderDetailSeckill orderDetailSeckill = new OrderDetailSeckill();
        orderDetailSeckill.setSeckillId(info.getId());
        orderDetailSeckill.setOrderId(orderInfo.getId());
        orderDetailSeckill.setPrice(info.getPrice());
        orderDetailSeckill.setUserId(userId);
        orderDetailSeckill.setConstPrice(info.getConstPrice());
        orderDetailSeckill.setSeckillNumber(seckillNumber);
        orderDetailSeckillService.save(orderDetailSeckill);

        orderStatusLogService.updateState(orderInfo.getId(), orderInfo.getOrderStatus());
        rabbitTemplate.convertAndSend("ttl_exchange", "ttl.message", orderInfo.getId());

        log.info("创建秒杀订单的返回{}", orderService.getById(orderInfo.getId()));
        return Result.success(orderService.getById(orderInfo.getId()));

    }

    @Override
    public Result getAdminPage(Long id, String name, Boolean hasStock, Integer seckillState, Long page, Long pageSize) {
        IPage<SeckillInfo> iPage = new Page<>(page, pageSize);
        QueryWrapper<SeckillInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("bit", 1);
        if (id != null) wrapper.likeRight("id", id);
        if (name != null) wrapper.like("name", name);
        if (hasStock != null) {
            if (hasStock) {
                wrapper.gt("stock", 0);
            } else {
                wrapper.eq("stock", 0);
            }
        }
        if (seckillState != null) {
            if (seckillState == 0) {
                wrapper.ge("begin_time", LocalDateTime.now());
            } else if (seckillState == 1) {
                wrapper.le("begin_time", LocalDateTime.now()).ge("end_time", LocalDateTime.now());
            } else if (seckillState == 2) {
                wrapper.le("end_time", LocalDateTime.now());
            }
        }

        IPage<SeckillInfo> seckillPage = seckillInfoMapper.selectPage(iPage, wrapper);
        List<BatchSeckillInfoDTO> batchSeckillInfoDTOList = new ArrayList<>();

        for (SeckillInfo record : seckillPage.getRecords()) {
            BatchSeckillInfoDTO batchSeckillInfoDTO = BeanUtil.copyProperties(record, BatchSeckillInfoDTO.class);
            batchSeckillInfoDTO.setSales(record.getNum() - record.getStock());
            if (batchSeckillInfoDTO.getBeginTime().isAfter(LocalDateTime.now()))
                batchSeckillInfoDTO.setSeckillState(0);
            else if (batchSeckillInfoDTO.getEndTime().isBefore(LocalDateTime.now())) {
                batchSeckillInfoDTO.setSeckillState(2);
            } else
                batchSeckillInfoDTO.setSeckillState(1);
            batchSeckillInfoDTOList.add(batchSeckillInfoDTO);
        }


        PageDTO<BatchSeckillInfoDTO> batchSeckillInfoPageDTO = new PageDTO<>();
        batchSeckillInfoPageDTO.setRows(batchSeckillInfoDTOList);
        batchSeckillInfoPageDTO.setPageSize(seckillPage.getSize());
        batchSeckillInfoPageDTO.setCurrentPage(seckillPage.getCurrent());
        batchSeckillInfoPageDTO.setPages(seckillPage.getPages());
        batchSeckillInfoPageDTO.setTotalSize(seckillPage.getTotal());
        return Result.success(batchSeckillInfoPageDTO);
    }


}
